use std::sync::{Arc, Mutex};

use datasource_connector::connector::SimpleDataSourceConnector;
use generator_engine::tera::TeraEngine;
use model_graph_types::{
    database::DataSource,
    datasource::{AttributeConditionBuilder, DataSourceConnector, QueryConditionBuilder},
    generator::CodeGenerator,
    modeling::{system_meta_database, ClassGetter, ComparsionOperator, DataSourceEntity, Value},
};

use crate::workflow::context::{Getter, WorkflowContext};

/// 带变量的文本取值
pub async fn query_value_with_variables(
    text: &String,
    context: Arc<Mutex<WorkflowContext>>,
) -> anyhow::Result<String> {
    //
    let engine = TeraEngine::default();
    let arguments = Value::Object(context.get_map_values(Some(String::from("N")))?);
    if text.contains("{{") {
        let prompt_new = text.replace("{{#", "{{N").replace("#}}", "}}");
        let prompt_str = engine.simple(arguments.clone(), &prompt_new).await?;
        tracing::debug!("{}:{}", prompt_new, prompt_str);
        Ok(prompt_str)
    } else {
        Ok(text.clone())
    }
}

async fn datasource(ds: &String) -> anyhow::Result<DataSource> {
    let sdsc = SimpleDataSourceConnector::default();
    let meta = system_meta_database()?;

    //ds identifier 查询
    let entity: DataSourceEntity = sdsc
        .instance_query_one(
            &Some(meta.clone()),
            &meta,
            &DataSourceEntity::get_identifier()?,
            QueryConditionBuilder::default()
                .attributes(vec![AttributeConditionBuilder::default()
                    .name("identifier")
                    .operator(ComparsionOperator::Equal)
                    .value(ds.clone())
                    .build()?])
                .build()?,
            None,
            None,
        )
        .await?
        .try_into()?;

    Ok(entity.datasource()?)
}

pub async fn datasource_by_id(
    ds_option: &Option<String>,
    context: Arc<Mutex<WorkflowContext>>,
) -> anyhow::Result<DataSource> {
    let meta = system_meta_database()?;

    let datasource = if let Some(ds) = ds_option {
        let dss = query_value_with_variables(ds, context.clone()).await?;
        datasource(&dss).await?
    } else {
        meta.clone()
    };
    Ok(datasource)
}
